﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace PrimitiveEngine.Primitives
{
    public class PEPolygon : PEPrimitive
    {
        public Vector3[] Points;
        public float Width { get { return width; } }
        public float Height { get { return height; } }

        public override int PrimitiveCount { get { return primitiveCount; } }

        // holds the actual vertices for drawing
        private Vector3[] tempArray1;
        private Vector3[] tempArray2;
        private int primitiveCount;
        private float width;
        private float height;
        private int numOfVertices;
        private bool isConvex;

        public PEPolygon(List<Vector2> points)
        {
            float minX = 0f;
            float maxX = 0f;
            float minY = 0f;
            float maxY = 0f;
            
            Type = PEPrimitiveType.Polygon;
            Points = new Vector3[points.Count];
            tempArray1 = new Vector3[points.Count];
            tempArray2 = new Vector3[points.Count];

            for (int i = 0; i < points.Count; i++)
            {
                Points[i] = new Vector3(points[i], 0);

                // set width and height
                if (minX > points[i].X)
                    minX = points[i].X;
                if (maxX < points[i].X)
                    maxX = points[i].X;
                if (minY > points[i].Y)
                    minY = points[i].Y;
                if (maxY < points[i].Y)
                    maxY = points[i].Y;
            }
            width = maxX - minX;
            height = maxY - minY;
            numOfVertices = points.Count;
            isConvex = IsConvex();
            BorderColor = Color.White;
        }

        public bool IsConvex()
        {
            bool isPositive = false;

            for (int i = 0; i < numOfVertices; ++i)
            {
                int lower = (i == 0) ? (numOfVertices - 1) : (i - 1);
                int middle = i;
                int upper = (i == numOfVertices - 1) ? (0) : (i + 1);

                float dx0 = Points[middle].X - Points[lower].X;
                float dy0 = Points[middle].Y - Points[lower].Y;
                float dx1 = Points[upper].X - Points[middle].X;
                float dy1 = Points[upper].Y - Points[middle].Y;

                float cross = dx0 * dy1 - dx1 * dy0;
                // Cross product should have same sign
                // for each vertex if poly is convex.
                bool newIsP = (cross >= 0) ? true : false;
                if (i == 0)
                {
                    isPositive = newIsP;
                }
                else if (isPositive != newIsP)
                {
                    return false;
                }
            }
            return true;
        }


        public void Decompose(out List<PEPolygon> polygons)
        {
            throw new NotImplementedException();
        }

        public override bool Intersection(PEPrimitive primitive)
        {
            throw new NotImplementedException();
        }
         
        public override bool Inside(Vector2 point)
        {
            throw new NotImplementedException();
        }

        public override void CreateUV()
        {
            throw new NotImplementedException();
        }

        public override void Draw(ref VertexPositionColorTexture[] vertices, ref int vertexIndex, ref short[] indices, ref int indiceIndex)
        {
            primitiveCount = 0;
            
            float scaleX = (Width - BorderWidth * 2) / Width;
            float scaleY = (Height - BorderWidth * 2) / Height;

            Matrix mat = Matrix.CreateScale(scaleX, scaleY, 1) * Matrix.CreateRotationZ(Rotation) * Matrix.CreateTranslation(new Vector3(Position, -Layer));

            Vector3.Transform(Points, ref mat, tempArray2);

            if (isConvex)
            {
                if (IsFilled)
                {
                    // simple fan render
                    for (int i = 1; i < numOfVertices - 1; i++)
                    {
                        vertices[vertexIndex].Position = tempArray2[0];
                        vertices[vertexIndex].Color = FillColor;
                        vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                        vertexIndex++;

                        vertices[vertexIndex].Position = tempArray2[i];
                        vertices[vertexIndex].Color = FillColor;
                        vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                        vertexIndex++;

                        vertices[vertexIndex].Position = tempArray2[i + 1];
                        vertices[vertexIndex].Color = FillColor;
                        vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                        vertexIndex++;

                        indices[indiceIndex + 0] = (short)(vertexIndex - 3);
                        indices[indiceIndex + 1] = (short)(vertexIndex - 2);
                        indices[indiceIndex + 2] = (short)(vertexIndex - 1);

                        indiceIndex += 3;

                        primitiveCount++;
                    }
                }
                if (BorderWidth > 0)
                {
                    mat = Matrix.CreateRotationZ(Rotation) * Matrix.CreateTranslation(new Vector3(Position, -Layer));

                    Vector3.Transform(Points, ref mat, tempArray1);

                    for (int i = 0; i < numOfVertices; i++)
                    {
                        int index = vertexIndex;
                        // 0
                        vertices[vertexIndex].Position = tempArray1[i];
                        vertices[vertexIndex].Color = BorderColor;
                        vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                        vertexIndex++;
                        // 1
                        vertices[vertexIndex].Position = tempArray2[i];
                        vertices[vertexIndex].Color = BorderColor;
                        vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                        vertexIndex++;
                        // 2
                        if (i == numOfVertices - 1)
                        {
                            vertices[vertexIndex].Position = tempArray1[0];
                            vertices[vertexIndex].Color = BorderColor;
                            vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                            vertexIndex++;
                            // 3
                            vertices[vertexIndex].Position = tempArray2[0];
                            vertices[vertexIndex].Color = BorderColor;
                            vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                            vertexIndex++;
                        }
                        else
                        {
                            vertices[vertexIndex].Position = tempArray1[i + 1];
                            vertices[vertexIndex].Color = BorderColor;
                            vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                            vertexIndex++;
                            // 3
                            vertices[vertexIndex].Position = tempArray2[i + 1];
                            vertices[vertexIndex].Color = BorderColor;
                            vertices[vertexIndex].TextureCoordinate = Vector2.Zero;
                            vertexIndex++;
                        }

                        indices[indiceIndex++] = (short)(index + 0);
                        indices[indiceIndex++] = (short)(index + 2);
                        indices[indiceIndex++] = (short)(index + 1);

                        indices[indiceIndex++] = (short)(index + 2);
                        indices[indiceIndex++] = (short)(index + 3);
                        indices[indiceIndex++] = (short)(index + 1);

                        primitiveCount += 2;
                    }
                }
            }
        }
    }
}
